home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / gnuplot-.5 / gnuplot- / gnuplot / win / wtext.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-16  |  48.4 KB  |  1,794 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: wtext.c%v 3.50.1.13 1993/08/19 03:21:26 woo Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - win/wtext.c */
  6. /*
  7.  * Copyright (C) 1992   Russell Lang
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Russell Lang
  25.  * 
  26.  * Send your comments or suggestions to 
  27.  *  info-gnuplot@dartmouth.edu.
  28.  * This is a mailing list; to join it send a note to 
  29.  *  info-gnuplot-request@dartmouth.edu.  
  30.  * Send bug reports to
  31.  *  bug-gnuplot@dartmouth.edu.
  32.  */
  33.  
  34. /* WARNING: Do not write to stdout/stderr with functions not listed 
  35.    in win/wtext.h */
  36.  
  37. #define STRICT
  38. #include <windows.h>
  39. #include <windowsx.h>
  40. #if WINVER >= 0x030a
  41. #include <commdlg.h>
  42. #endif
  43. #include <string.h>    /* use only far items */
  44. #ifndef __MSC__
  45. #include <mem.h>
  46. #endif
  47. #include <stdlib.h>
  48. #include <ctype.h>
  49. #include <dos.h>
  50.  
  51. #include "wgnuplib.h"
  52. #include "wresourc.h"
  53. #include "wcommon.h"
  54.  
  55. /* font stuff */
  56. #define TEXTFONTSIZE 9
  57. #define TEXTFONTNAME "Terminal"
  58.  
  59. #define EOF -1        /* instead of using <stdio.h> */
  60. /* limits */
  61. #define MAXSTR 256
  62. POINT ScreenMinSize = {16,4};
  63. LRESULT CALLBACK _export WndParentProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  64. LRESULT CALLBACK _export WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  65. void ReadTextIni(LPTW lptw);
  66. void LimitMark(LPTW lptw, POINT FAR *lppt);
  67.  
  68. char szNoMemory[] = "out of memory";
  69. COLORREF TextColorTable[16] = { 
  70.     RGB(0,0,0),            /* black */
  71.     RGB(0,0,128),        /* dark blue */
  72.     RGB(0,128,0),        /* dark green */
  73.     RGB(0,128,128),        /* dark cyan */
  74.     RGB(128,0,0),        /* dark red */
  75.     RGB(128,0,128),        /* dark magenta */
  76.     RGB(128,128,0),        /* dark yellow */
  77.     RGB(128,128,128),    /* dark grey */
  78.     RGB(192,192,192),    /* light grey */
  79.     RGB(0,0,255),        /* blue */
  80.     RGB(0,255,0),        /* green */
  81.     RGB(0,255,255),        /* cyan */
  82.     RGB(255,0,0),        /* red */
  83.     RGB(255,0,255),        /* magenta */
  84.     RGB(255,255,0),        /* yellow */
  85.     RGB(255,255,255),    /* white */
  86. };
  87. #define NOTEXT 0xF0
  88. #define MARKFORE RGB(255,255,255)
  89. #define MARKBACK RGB(0,0,128)
  90. #define TextFore(attr) TextColorTable[(attr) & 15]
  91. #define TextBack(attr) TextColorTable[(attr>>4) & 15]
  92.  
  93.  
  94. void WDPROC
  95. TextMessage(void)
  96. {
  97.     MSG msg;
  98.  
  99.     while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  100.         {
  101.         TranslateMessage(&msg);
  102.         DispatchMessage(&msg);
  103.         }
  104.     return;
  105. }
  106.  
  107.  
  108.  
  109. void
  110. CreateTextClass(LPTW lptw)
  111. {
  112. WNDCLASS wndclass;
  113.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  114.     wndclass.lpfnWndProc = WndTextProc;
  115.     wndclass.cbClsExtra = 0;
  116.     wndclass.cbWndExtra = 2 * sizeof(void FAR *);
  117.     wndclass.hInstance = lptw->hInstance;
  118.     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  119.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  120.     wndclass.hbrBackground = NULL;
  121.     lptw->hbrBackground = CreateSolidBrush(lptw->bSysColors ? 
  122.         GetSysColor(COLOR_WINDOW) : RGB(0,0,0));
  123.     wndclass.lpszMenuName = NULL;
  124.     wndclass.lpszClassName = szTextClass;
  125.     RegisterClass(&wndclass);
  126.  
  127.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  128.     wndclass.lpfnWndProc = WndParentProc;
  129.     wndclass.cbClsExtra = 0;
  130.     wndclass.cbWndExtra = 2 * sizeof(void FAR *);
  131.     wndclass.hInstance = lptw->hInstance;
  132.     if (lptw->hIcon)
  133.         wndclass.hIcon = lptw->hIcon;
  134.     else
  135.         wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  136.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  137.     wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
  138.     wndclass.lpszMenuName = NULL;
  139.     wndclass.lpszClassName = szParentClass;
  140.     RegisterClass(&wndclass);
  141. }
  142.  
  143.  
  144. /* make text window */
  145. int WDPROC
  146. TextInit(LPTW lptw)
  147. {
  148.     RECT rect;
  149.     HMENU sysmenu;
  150.     HGLOBAL hglobal;
  151.     char buf[80];
  152.     
  153.     ReadTextIni(lptw);
  154.  
  155.     if (!lptw->hPrevInstance)
  156.         CreateTextClass(lptw);
  157.  
  158.     if (lptw->KeyBufSize == 0)
  159.         lptw->KeyBufSize = 256;
  160.  
  161.     if (lptw->ScreenSize.x < ScreenMinSize.x)
  162.         lptw->ScreenSize.x = ScreenMinSize.x;
  163.     if (lptw->ScreenSize.y < ScreenMinSize.y)
  164.         lptw->ScreenSize.y = ScreenMinSize.y;
  165.  
  166.     lptw->CursorPos.x = lptw->CursorPos.y = 0;
  167.     lptw->bFocus = FALSE;
  168.     lptw->bGetCh = FALSE;
  169.     lptw->CaretHeight = 0;
  170.     if (!lptw->nCmdShow)
  171.         lptw->nCmdShow = SW_SHOWNORMAL;
  172.     if (!lptw->Attr)
  173.         lptw->Attr = 0xf0;    /* black on white */
  174.  
  175.     hglobal = GlobalAlloc(GHND, lptw->ScreenSize.x * lptw->ScreenSize.y);
  176.     lptw->ScreenBuffer = (BYTE FAR *)GlobalLock(hglobal);
  177.     if (lptw->ScreenBuffer == (BYTE FAR *)NULL) {
  178.         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  179.         return(1);
  180.     }
  181.     _fmemset(lptw->ScreenBuffer, ' ', lptw->ScreenSize.x * lptw->ScreenSize.y);
  182.     hglobal = GlobalAlloc(GHND, lptw->ScreenSize.x * lptw->ScreenSize.y);
  183.     lptw->AttrBuffer = (BYTE FAR *)GlobalLock(hglobal);
  184.     if (lptw->AttrBuffer == (BYTE FAR *)NULL) {
  185.         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  186.         return(1);
  187.     }
  188.     _fmemset(lptw->AttrBuffer, NOTEXT, lptw->ScreenSize.x * lptw->ScreenSize.y);
  189.     hglobal = GlobalAlloc(LHND, lptw->KeyBufSize);
  190.     lptw->KeyBuf = (BYTE FAR *)GlobalLock(hglobal);
  191.     if (lptw->KeyBuf == (BYTE FAR *)NULL) {
  192.         MessageBox((HWND)NULL,szNoMemory,(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  193.         return(1);
  194.     }
  195.     lptw->KeyBufIn = lptw->KeyBufOut = lptw->KeyBuf;
  196.  
  197.     lptw->hWndParent = CreateWindow(szParentClass, lptw->Title,
  198.           WS_OVERLAPPEDWINDOW,
  199.           lptw->Origin.x, lptw->Origin.y,
  200.           lptw->Size.x, lptw->Size.y,
  201.           NULL, NULL, lptw->hInstance, lptw);
  202.     if (lptw->hWndParent == (HWND)NULL) {
  203.         MessageBox((HWND)NULL,"Couldn't open parent text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  204.         return(1);
  205.     }
  206.     ShowWindow(lptw->hWndParent, lptw->nCmdShow);
  207.     GetClientRect(lptw->hWndParent, &rect);
  208.  
  209.     lptw->hWndText = CreateWindow(szTextClass, lptw->Title,
  210.           WS_CHILD | WS_VSCROLL | WS_HSCROLL,
  211.           0, lptw->ButtonHeight,
  212.           rect.right, rect.bottom-lptw->ButtonHeight,
  213.           lptw->hWndParent, NULL, lptw->hInstance, lptw);
  214.     if (lptw->hWndText == (HWND)NULL) {
  215.         MessageBox((HWND)NULL,"Couldn't open text window",(LPSTR)NULL, MB_ICONHAND | MB_SYSTEMMODAL);
  216.         return(1);
  217.     }
  218.  
  219.     lptw->hPopMenu = CreatePopupMenu();
  220.     AppendMenu(lptw->hPopMenu, MF_STRING, M_COPY_CLIP, "&Copy to Clipboard");
  221.     AppendMenu(lptw->hPopMenu, MF_STRING, M_PASTE, "&Paste");
  222. #if WINVER >= 0x030a
  223.     AppendMenu(lptw->hPopMenu, MF_STRING, M_CHOOSE_FONT, "Choose &Font...");
  224. #endif
  225.     AppendMenu(lptw->hPopMenu, MF_STRING | (lptw->bSysColors ? MF_CHECKED : MF_UNCHECKED), 
  226.         M_SYSCOLORS, "&System Colors");
  227.     if (lptw->IniFile != (LPSTR)NULL) {
  228.         wsprintf(buf,"&Update %s",lptw->IniFile);
  229.         AppendMenu(lptw->hPopMenu, MF_STRING, M_WRITEINI, (LPSTR)buf);
  230.     }
  231.  
  232.     sysmenu = GetSystemMenu(lptw->hWndParent,0);    /* get the sysmenu */
  233.     AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
  234.     AppendMenu(sysmenu, MF_POPUP, (UINT)lptw->hPopMenu, "&Options");
  235.     AppendMenu(sysmenu, MF_STRING, M_ABOUT, "&About");
  236.  
  237.     if (lptw->lpmw)
  238.         LoadMacros(lptw);
  239.  
  240.     ShowWindow(lptw->hWndText, SW_SHOWNORMAL);
  241.     BringWindowToTop(lptw->hWndText);
  242.     SetFocus(lptw->hWndText);
  243.     TextMessage();
  244.     return(0);
  245. }
  246.  
  247. /* close a text window */
  248. void WDPROC
  249. TextClose(LPTW lptw)
  250. {
  251.     HGLOBAL hglobal;
  252.  
  253.     /* close window */
  254.     if (lptw->hWndParent)
  255.         DestroyWindow(lptw->hWndParent);
  256.     TextMessage();
  257.  
  258.     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->ScreenBuffer) );
  259.     if (hglobal) {
  260.         GlobalUnlock(hglobal);
  261.         GlobalFree(hglobal);
  262.     }
  263.     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->AttrBuffer) );
  264.     if (hglobal) {
  265.         GlobalUnlock(hglobal);
  266.         GlobalFree(hglobal);
  267.     }
  268.     hglobal = (HGLOBAL)GlobalHandle( SELECTOROF(lptw->KeyBuf) );
  269.     if (hglobal) {
  270.         GlobalUnlock(hglobal);
  271.         GlobalFree(hglobal);
  272.     }
  273.  
  274.     if (lptw->lpmw)
  275.         CloseMacros(lptw);
  276.     lptw->hWndParent = (HWND)NULL;
  277. }
  278.     
  279. void
  280. WriteTextIni(LPTW lptw)
  281. {
  282.     RECT rect;
  283.     LPSTR file = lptw->IniFile;
  284.     LPSTR section = lptw->IniSection;
  285.     char profile[80];
  286.     int iconic;
  287.  
  288.     
  289.     if ((file == (LPSTR)NULL) || (section == (LPSTR)NULL))
  290.         return;
  291.     
  292.     iconic = IsIconic(lptw->hWndParent);
  293.     if (iconic)
  294.         ShowWindow(lptw->hWndParent, SW_SHOWNORMAL);
  295.     GetWindowRect(lptw->hWndParent,&rect);
  296.     wsprintf(profile, "%d %d", rect.left, rect.top);
  297.     WritePrivateProfileString(section, "TextOrigin", profile, file);
  298.     wsprintf(profile, "%d %d", rect.right-rect.left, rect.bottom-rect.top);
  299.     WritePrivateProfileString(section, "TextSize", profile, file);
  300.     wsprintf(profile, "%d", iconic);
  301.     WritePrivateProfileString(section, "TextMinimized", profile, file);
  302.     wsprintf(profile, "%s,%d", lptw->fontname, lptw->fontsize);
  303.     WritePrivateProfileString(section, "TextFont", profile, file);
  304.     wsprintf(profile, "%d", lptw->bSysColors);
  305.     WritePrivateProfileString(section, "SysColors", profile, file);
  306.     if (iconic)
  307.         ShowWindow(lptw->hWndParent, SW_SHOWMINIMIZED);
  308.     return;
  309. }
  310.  
  311. void
  312. ReadTextIni(LPTW lptw)
  313. {
  314.     LPSTR file = lptw->IniFile;
  315.     LPSTR section = lptw->IniSection;
  316.     char profile[81];
  317.     LPSTR p;
  318.     BOOL bOKINI;
  319.  
  320.     bOKINI = (file != (LPSTR)NULL) && (section != (LPSTR)NULL);
  321.     profile[0] = '\0';
  322.  
  323.     if (bOKINI)
  324.       GetPrivateProfileString(section, "TextOrigin", "", profile, 80, file);
  325.     if ( (p = GetInt(profile, &lptw->Origin.x)) == NULL)
  326.         lptw->Origin.x = CW_USEDEFAULT;
  327.     if ( (p = GetInt(p, &lptw->Origin.y)) == NULL)
  328.         lptw->Origin.y = CW_USEDEFAULT;
  329.     if ( (file != (LPSTR)NULL) && (section != (LPSTR)NULL) )
  330.       GetPrivateProfileString(section, "TextSize", "", profile, 80, file);
  331.     if ( (p = GetInt(profile, &lptw->Size.x)) == NULL)
  332.         lptw->Size.x = CW_USEDEFAULT;
  333.     if ( (p = GetInt(p, &lptw->Size.y)) == NULL)
  334.         lptw->Size.y = CW_USEDEFAULT;
  335.  
  336.     if (bOKINI)
  337.       GetPrivateProfileString(section, "TextFont", "", profile, 80, file);
  338.     {
  339.         char FAR *size;
  340.         size = _fstrchr(profile,',');
  341.         if (size) {
  342.             *size++ = '\0';
  343.             if ( (p = GetInt(size, &lptw->fontsize)) == NULL)
  344.                 lptw->fontsize = TEXTFONTSIZE;
  345.         }
  346.         _fstrcpy(lptw->fontname, profile);
  347.         if (lptw->fontsize == 0)
  348.             lptw->fontsize = TEXTFONTSIZE;
  349.         if (!(*lptw->fontname))
  350.             _fstrcpy(lptw->fontname,TEXTFONTNAME);
  351.     }
  352.  
  353.     if (bOKINI) {
  354.         int iconic;
  355.         GetPrivateProfileString(section, "TextMinimized", "", profile, 80, file);
  356.         if ((p = GetInt(profile, &iconic)) == NULL)
  357.             iconic = 0;
  358.         if (iconic)
  359.             lptw->nCmdShow = SW_SHOWMINIMIZED;
  360.     }
  361.     lptw->bSysColors = FALSE;
  362.     GetPrivateProfileString(section, "SysColors", "", profile, 80, file);
  363.     if ((p = GetInt(profile, &lptw->bSysColors)) == NULL)
  364.         lptw->bSysColors = 0;
  365. }
  366.  
  367.  
  368. /* Bring Cursor into text window */
  369. void WDPROC
  370. TextToCursor(LPTW lptw)
  371. {
  372. int nXinc=0;
  373. int nYinc=0;
  374. int cxCursor;
  375. int cyCursor;
  376.     cyCursor = lptw->CursorPos.y * lptw->CharSize.y;
  377.     if ( (cyCursor + lptw->CharSize.y > lptw->ScrollPos.y + lptw->ClientSize.y) 
  378.       || (cyCursor < lptw->ScrollPos.y) ) {
  379.         nYinc = max(0, cyCursor + lptw->CharSize.y - lptw->ClientSize.y) - lptw->ScrollPos.y;
  380.         nYinc = min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y);
  381.     }
  382.     cxCursor = lptw->CursorPos.x * lptw->CharSize.x;
  383.     if ( (cxCursor + lptw->CharSize.x > lptw->ScrollPos.x + lptw->ClientSize.x)
  384.       || (cxCursor < lptw->ScrollPos.x) ) {
  385.         nXinc = max(0, cxCursor + lptw->CharSize.x - lptw->ClientSize.x/2) - lptw->ScrollPos.x;
  386.         nXinc = min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x);
  387.     }
  388.     if (nYinc || nXinc) {
  389.         lptw->ScrollPos.y += nYinc;
  390.         lptw->ScrollPos.x += nXinc;
  391.         ScrollWindow(lptw->hWndText,-nXinc,-nYinc,NULL,NULL);
  392.         SetScrollPos(lptw->hWndText,SB_VERT,lptw->ScrollPos.y,TRUE);
  393.         SetScrollPos(lptw->hWndText,SB_HORZ,lptw->ScrollPos.x,TRUE);
  394.         UpdateWindow(lptw->hWndText);
  395.     }
  396. }
  397.  
  398. void
  399. NewLine(LPTW lptw)
  400. {
  401.     lptw->CursorPos.x = 0;
  402.     lptw->CursorPos.y++;
  403.     if (lptw->CursorPos.y >= lptw->ScreenSize.y) {
  404.         int i =  lptw->ScreenSize.x * (lptw->ScreenSize.y - 1);
  405.         _fmemmove(lptw->ScreenBuffer, lptw->ScreenBuffer+lptw->ScreenSize.x, i);
  406.         _fmemset(lptw->ScreenBuffer + i, ' ', lptw->ScreenSize.x);
  407.         _fmemmove(lptw->AttrBuffer, lptw->AttrBuffer+lptw->ScreenSize.x, i);
  408.         _fmemset(lptw->AttrBuffer + i, NOTEXT, lptw->ScreenSize.x);
  409.         lptw->CursorPos.y--;
  410.         ScrollWindow(lptw->hWndText,0,-lptw->CharSize.y,NULL,NULL);
  411.         lptw->MarkBegin.y--;
  412.         lptw->MarkEnd.y--;
  413.         LimitMark(lptw, &lptw->MarkBegin);
  414.         LimitMark(lptw, &lptw->MarkEnd);
  415.         UpdateWindow(lptw->hWndText);
  416.     }
  417.     if (lptw->CursorFlag)
  418.         TextToCursor(lptw);
  419.     TextMessage();
  420. }
  421.  
  422. /* Update count characters in window at cursor position */
  423. /* Updates cursor position */
  424. void
  425. UpdateText(LPTW lptw, int count)
  426. {
  427. HDC hdc;
  428. int xpos, ypos;
  429.     xpos = lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x;
  430.     ypos = lptw->CursorPos.y*lptw->CharSize.y - lptw->ScrollPos.y;
  431.     hdc = GetDC(lptw->hWndText);
  432.     if (lptw->bSysColors) {
  433.         SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  434.         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  435.     }
  436.     else {
  437.         SetTextColor(hdc, TextFore(lptw->Attr));
  438.         SetBkColor(hdc, TextBack(lptw->Attr));
  439.     }
  440.     SelectFont(hdc, lptw->hfont);
  441.     TextOut(hdc,xpos,ypos,
  442.         (LPSTR)(lptw->ScreenBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + 
  443.         lptw->CursorPos.x), count);
  444.     (void)ReleaseDC(lptw->hWndText,hdc);
  445.     lptw->CursorPos.x += count;
  446.     if (lptw->CursorPos.x >= lptw->ScreenSize.x)
  447.         NewLine(lptw);
  448. }
  449.  
  450. int WDPROC
  451. TextPutCh(LPTW lptw, BYTE ch)
  452. {
  453. int pos;
  454.     switch(ch) {
  455.         case '\r':
  456.             lptw->CursorPos.x = 0;
  457.             if (lptw->CursorFlag)
  458.                 TextToCursor(lptw);
  459.             break;
  460.         case '\n':
  461.             NewLine(lptw);
  462.             break;
  463.         case 7:
  464.             MessageBeep(-1);
  465.             if (lptw->CursorFlag)
  466.                 TextToCursor(lptw);
  467.             break;
  468.         case '\t':
  469.             {
  470.             int n;
  471.                 for ( n = 8 - (lptw->CursorPos.x % 8); n>0; n-- )
  472.                     TextPutCh(lptw, ' ');
  473.             }
  474.             break;
  475.         case 0x08:
  476.         case 0x7f:
  477.             lptw->CursorPos.x--;
  478.             if (lptw->CursorPos.x < 0) {
  479.                 lptw->CursorPos.x = lptw->ScreenSize.x - 1;
  480.                 lptw->CursorPos.y--;
  481.             }
  482.             if (lptw->CursorPos.y < 0)
  483.                 lptw->CursorPos.y = 0;
  484.             break;
  485.         default:
  486.             pos = lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
  487.             lptw->ScreenBuffer[pos] = ch;
  488.             lptw->AttrBuffer[pos] = lptw->Attr;
  489.             UpdateText(lptw, 1);
  490.     }
  491.     return ch;
  492. }
  493.  
  494. void 
  495. TextPutStr(LPTW lptw, LPSTR str)
  496. {
  497. BYTE FAR *p, FAR *pa;
  498. int count, limit;
  499.     while (*str) {
  500.         p = lptw->ScreenBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
  501.         pa = lptw->AttrBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
  502.         limit = lptw->ScreenSize.x - lptw->CursorPos.x;
  503.         for (count=0; (count < limit) && *str && (isprint(*str) || *str=='\t'); count++) {
  504.             if (*str=='\t') {
  505.                 int n;
  506.                 for ( n = 8 - ((lptw->CursorPos.x+count) % 8); (count < limit) & (n>0); n--, count++ ) {
  507.                     *p++ = ' ';
  508.                     *pa++ = lptw->Attr;
  509.                 }
  510.                 str++;
  511.                 count--;
  512.             }
  513.             else {
  514.                 *p++ = *str++;
  515.                 *pa++ = lptw->Attr;
  516.             }
  517.         }
  518.         if (count>0) {
  519.             UpdateText(lptw, count);
  520.         }
  521.         if (*str=='\n') {
  522.             NewLine(lptw);
  523.             str++;
  524.         }
  525.         else if (*str && !isprint(*str) && *str!='\t') {
  526.             TextPutCh(lptw, *str++);
  527.         }
  528.     }
  529. }
  530.  
  531.  
  532. void
  533. LimitMark(LPTW lptw, POINT FAR *lppt)
  534. {
  535.     if (lppt->x < 0)
  536.         lppt->x = 0;
  537.     if (lppt->y < 0) {
  538.         lppt->x = 0;
  539.         lppt->y = 0;
  540.     }
  541.     if (lppt->x > lptw->ScreenSize.x)
  542.         lppt->x = lptw->ScreenSize.x;
  543.     if (lppt->y >= lptw->ScreenSize.y) {
  544.         lppt->x = 0;
  545.         lppt->y = lptw->ScreenSize.y;
  546.     }
  547. }
  548.  
  549. void
  550. ClearMark(LPTW lptw, POINT pt)
  551. {
  552. RECT rect1, rect2, rect3;
  553. int tmp;
  554.   if ((lptw->MarkBegin.x != lptw->MarkEnd.x) || 
  555.       (lptw->MarkBegin.y != lptw->MarkEnd.y) ) {
  556.     if (lptw->MarkBegin.x > lptw->MarkEnd.x) {
  557.         tmp = lptw->MarkBegin.x;
  558.         lptw->MarkBegin.x = lptw->MarkEnd.x;
  559.         lptw->MarkEnd.x = tmp;
  560.     }
  561.     if (lptw->MarkBegin.y > lptw->MarkEnd.y) {
  562.         tmp = lptw->MarkBegin.y;
  563.         lptw->MarkBegin.y = lptw->MarkEnd.y;
  564.         lptw->MarkEnd.y = tmp;
  565.     }
  566.     /* calculate bounding rectangle in character coordinates */
  567.     if (lptw->MarkBegin.y != lptw->MarkEnd.y) {
  568.         rect1.left = 0;
  569.         rect1.right = lptw->ScreenSize.x;
  570.     }
  571.     else {
  572.         rect1.left = lptw->MarkBegin.x;
  573.         rect1.right = lptw->MarkEnd.x + 1;
  574.     }
  575.     rect1.top = lptw->MarkBegin.y;
  576.     rect1.bottom = lptw->MarkEnd.y + 1;
  577.     /* now convert to client coordinates */
  578.     rect1.left   = rect1.left   * lptw->CharSize.x - lptw->ScrollPos.x;
  579.     rect1.right  = rect1.right  * lptw->CharSize.x - lptw->ScrollPos.x;
  580.     rect1.top    = rect1.top    * lptw->CharSize.y - lptw->ScrollPos.y;
  581.     rect1.bottom = rect1.bottom * lptw->CharSize.y - lptw->ScrollPos.y;
  582.     /* get client rect and calculate intersection */
  583.     GetClientRect(lptw->hWndText, &rect2);
  584.     IntersectRect(&rect3,  &rect1, &rect2);
  585.     /* update window if necessary */
  586.     if (!IsRectEmpty(&rect3)) {
  587.         InvalidateRect(lptw->hWndText, &rect3, TRUE);
  588.     }
  589.   }
  590.   LimitMark(lptw, &pt);
  591.   lptw->MarkBegin.x = lptw->MarkEnd.x = pt.x;
  592.   lptw->MarkBegin.y = lptw->MarkEnd.y = pt.y;
  593.   UpdateWindow(lptw->hWndText);
  594. }
  595.  
  596.  
  597. /* output a line including attribute changes as needed */
  598. void
  599. DoLine(LPTW lptw, HDC hdc, int xpos, int ypos, int offset, int count)
  600. {
  601.     BYTE FAR *pa, attr;
  602.     int idx, num;
  603.     pa = lptw->AttrBuffer + offset;
  604. if ((offset < 0) || (offset >= lptw->ScreenSize.x*lptw->ScreenSize.y))
  605. MessageBox((HWND)NULL, "panic", "panic", MB_OK | MB_ICONEXCLAMATION);
  606.     idx = 0;
  607.     num = count;
  608.     while (num > 0) {
  609.         attr = *pa;
  610.         while ((num > 0) && (attr == *pa)) {
  611.             /* skip over bytes with same attribute */
  612.             num--;
  613.             pa++;
  614.         }
  615.         if (lptw->bSysColors) {
  616.             SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  617.             SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  618.         }
  619.         else {
  620.             SetTextColor(hdc, TextFore(attr));
  621.             SetBkColor(hdc, TextBack(attr));
  622.         }
  623.         TextOut(hdc,xpos,ypos, (LPSTR)(lptw->ScreenBuffer + offset + idx),
  624.             count-num-idx);
  625.         xpos += lptw->CharSize.x * (count-num-idx);
  626.         idx = count-num;
  627.     }
  628. }
  629.  
  630. void
  631. DoMark(LPTW lptw, POINT pt, POINT end, BOOL mark)
  632. {
  633. int xpos, ypos;
  634. HDC hdc;
  635. int count;
  636. int offset;
  637.     offset = lptw->ScreenSize.x * pt.y + pt.x;
  638.     hdc = GetDC(lptw->hWndText);
  639.     SelectFont(hdc, lptw->hfont);
  640.     if (lptw->bSysColors) {
  641.         SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  642.         SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  643.     }
  644.     else {
  645.         SetTextColor(hdc, MARKFORE);
  646.         SetBkColor(hdc, MARKBACK);
  647.     }
  648.     while (pt.y < end.y) {
  649.         /* multiple lines */
  650.         xpos = pt.x*lptw->CharSize.x - lptw->ScrollPos.x;
  651.         ypos = pt.y*lptw->CharSize.y - lptw->ScrollPos.y;
  652.         count = lptw->ScreenSize.x - pt.x;
  653.         if (mark)
  654.             TextOut(hdc,xpos,ypos, (LPSTR)(lptw->ScreenBuffer + offset), count);
  655.         else {
  656.             DoLine(lptw, hdc, xpos, ypos, offset, count);
  657.             if (lptw->bSysColors) {
  658.                 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  659.                 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  660.             }
  661.             else {
  662.                 SetTextColor(hdc, MARKFORE);
  663.                 SetBkColor(hdc, MARKBACK);
  664.             }
  665.         }
  666.         offset += count;
  667.         pt.y++;
  668.         pt.x=0;
  669.     }
  670.     /* partial line */
  671.     xpos = pt.x*lptw->CharSize.x - lptw->ScrollPos.x;
  672.     ypos = pt.y*lptw->CharSize.y - lptw->ScrollPos.y;
  673.     count = end.x - pt.x;
  674.     if (end.y != lptw->ScreenSize.y) {
  675.         if (mark)
  676.             TextOut(hdc,xpos,ypos, (LPSTR)(lptw->ScreenBuffer + offset), count);
  677.         else
  678.             DoLine(lptw, hdc, xpos, ypos, offset, count);
  679.     }
  680.     (void)ReleaseDC(lptw->hWndText,hdc);
  681. }
  682.  
  683. void
  684. UpdateMark(LPTW lptw, POINT pt)
  685. {
  686. int begin, point, end;
  687.     LimitMark(lptw, &pt);
  688.     begin = lptw->ScreenSize.x*lptw->MarkBegin.y + lptw->MarkBegin.x;
  689.     point = lptw->ScreenSize.x*pt.y + pt.x;
  690.     end   = lptw->ScreenSize.x*lptw->MarkEnd.y + lptw->MarkEnd.x;
  691.  
  692.     if (begin <= end) {
  693.         /* forward mark */
  694.         if (point >= end) {
  695.             /* extend marked area */
  696.             DoMark(lptw, lptw->MarkEnd, pt, TRUE);
  697.         }
  698.         else if (point >= begin) {
  699.             /* retract marked area */
  700.             DoMark(lptw, pt, lptw->MarkEnd, FALSE);
  701.         }
  702.         else {    /* retract and reverse */
  703.             DoMark(lptw, lptw->MarkBegin, lptw->MarkEnd, FALSE);
  704.             DoMark(lptw, pt, lptw->MarkBegin, TRUE);
  705.         }
  706.     }
  707.     else {
  708.         /* reverse mark */
  709.         if (point <= end) {
  710.             /* extend marked area */
  711.             DoMark(lptw, pt, lptw->MarkEnd, TRUE);
  712.         }
  713.         else if (point <= begin) {
  714.             /* retract marked area */
  715.             DoMark(lptw, lptw->MarkEnd, pt, FALSE);
  716.         }
  717.         else {    /* retract and reverse */
  718.             DoMark(lptw, lptw->MarkEnd, lptw->MarkBegin, FALSE);
  719.             DoMark(lptw, lptw->MarkBegin, pt, TRUE);
  720.         }
  721.     }
  722.     lptw->MarkEnd.x = pt.x;
  723.     lptw->MarkEnd.y = pt.y;
  724. }
  725.  
  726.  
  727. #if WINVER >= 0x030a
  728. /* Windows 3.1 drag-drop feature */
  729. char szFile[80];
  730. void
  731. DragFunc(LPTW lptw, HDROP hdrop)
  732. {
  733.     int i, cFiles;
  734.     LPSTR p;
  735.     if ( (lptw->DragPre==(LPSTR)NULL) || (lptw->DragPost==(LPSTR)NULL) )
  736.         return;
  737.     cFiles = DragQueryFile(hdrop, 0xffff, (LPSTR)NULL, 0);
  738.     for (i=0; i<cFiles; i++) {
  739.         DragQueryFile(hdrop, i, szFile, 80);
  740.         for (p=lptw->DragPre; *p; p++)
  741.             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
  742.         for (p=szFile; *p; p++)
  743.             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
  744.         for (p=lptw->DragPost; *p; p++)
  745.             SendMessage(lptw->hWndText,WM_CHAR,*p,1L);
  746.     }
  747.     DragFinish(hdrop);
  748. }
  749. #endif
  750.  
  751.  
  752. void
  753. TextCopyClip(LPTW lptw)
  754. {
  755.     int size, count;
  756.     HGLOBAL hGMem;
  757.     LPSTR cbuf, cp;
  758.     POINT pt, end;
  759.     TEXTMETRIC tm;
  760.     UINT type;
  761.     HDC hdc;
  762.  
  763.     if ((lptw->MarkBegin.x == lptw->MarkEnd.x) && 
  764.         (lptw->MarkBegin.y == lptw->MarkEnd.y) ) {
  765.         /* copy user text */
  766.         return;
  767.     }
  768.  
  769.     size = (lptw->MarkEnd.y - lptw->MarkBegin.y + 1) 
  770.         * (lptw->ScreenSize.x + 2) + 1;
  771.     hGMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)size);
  772.     cbuf = cp = (LPSTR)GlobalLock(hGMem);
  773.     if (cp == (LPSTR)NULL)
  774.         return;
  775.     
  776.     pt.x = lptw->MarkBegin.x;
  777.     pt.y = lptw->MarkBegin.y;
  778.     end.x   = lptw->MarkEnd.x;
  779.     end.y   = lptw->MarkEnd.y;
  780.  
  781.     while (pt.y < end.y) {
  782.         /* copy to global buffer */
  783.         count = lptw->ScreenSize.x - pt.x;
  784.         _fmemcpy(cp, lptw->ScreenBuffer + lptw->ScreenSize.x*pt.y+pt.x, count);
  785.         /* remove trailing spaces */
  786.         for (count=count-1; count>=0; count--) {
  787.             if (cp[count]!=' ')
  788.                 break;
  789.             cp[count] = '\0';
  790.         }
  791.         cp[++count] = '\r';
  792.         cp[++count] = '\n';
  793.         cp[++count] = '\0';
  794.         cp += count;
  795.         pt.y++;
  796.         pt.x=0;
  797.     }
  798.     /* partial line */
  799.     count = end.x - pt.x;
  800.     if (end.y != lptw->ScreenSize.y) {
  801.         _fmemcpy(cp, lptw->ScreenBuffer + lptw->ScreenSize.x*pt.y+pt.x, count);
  802.         cp[count] = '\0';
  803.     }
  804.     size = _fstrlen(cbuf) + 1;
  805.     GlobalUnlock(hGMem);
  806.     hGMem = GlobalReAlloc(hGMem, (DWORD)size, GMEM_MOVEABLE);
  807.     /* find out what type to put into clipboard */
  808.     hdc = GetDC(lptw->hWndText);
  809.     SelectFont(hdc, lptw->hfont);
  810.     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
  811.     if (tm.tmCharSet == OEM_CHARSET)
  812.         type = CF_OEMTEXT;
  813.     else
  814.         type = CF_TEXT;
  815.     ReleaseDC(lptw->hWndText, hdc);
  816.     /* give buffer to clipboard */
  817.     OpenClipboard(lptw->hWndParent);
  818.     EmptyClipboard();
  819.     SetClipboardData(type, hGMem);
  820.     CloseClipboard();
  821. }
  822.  
  823. void
  824. TextMakeFont(LPTW lptw)
  825. {
  826.     LOGFONT lf;
  827.     TEXTMETRIC tm;
  828.     LPSTR p;
  829.     HDC hdc;
  830.  
  831.     hdc = GetDC(lptw->hWndText);
  832.     _fmemset(&lf, 0, sizeof(LOGFONT));
  833.     _fstrncpy(lf.lfFaceName,lptw->fontname,LF_FACESIZE);
  834.     lf.lfHeight = -MulDiv(lptw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  835.     lf.lfPitchAndFamily = FIXED_PITCH;
  836.     lf.lfCharSet = DEFAULT_CHARSET;
  837.     if ( (p = _fstrstr(lptw->fontname," Italic")) != (LPSTR)NULL ) {
  838.         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
  839.         lf.lfItalic = TRUE;
  840.     }
  841.     if ( (p = _fstrstr(lptw->fontname," Bold")) != (LPSTR)NULL ) {
  842.         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
  843.         lf.lfWeight = FW_BOLD;
  844.     }
  845.     if (lptw->hfont != 0)
  846.         DeleteFont(lptw->hfont);
  847.     lptw->hfont = CreateFontIndirect((LOGFONT FAR *)&lf);
  848.     /* get text size */
  849.     SelectFont(hdc, lptw->hfont);
  850.     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
  851.     lptw->CharSize.y = tm.tmHeight;
  852.     lptw->CharSize.x = tm.tmAveCharWidth;
  853.     lptw->CharAscent = tm.tmAscent;
  854.     if (lptw->bFocus)
  855.         CreateCaret(lptw->hWndText, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
  856.     ReleaseDC(lptw->hWndText, hdc);
  857.     return;
  858. }
  859.  
  860. void
  861. TextSelectFont(LPTW lptw) {
  862. #if WINVER >= 0x030a
  863.     LOGFONT lf;
  864.     CHOOSEFONT cf;
  865.     HDC hdc;
  866.     char lpszStyle[LF_FACESIZE]; 
  867.     LPSTR p;
  868.  
  869.     /* Set all structure fields to zero. */
  870.     _fmemset(&cf, 0, sizeof(CHOOSEFONT));
  871.     _fmemset(&lf, 0, sizeof(LOGFONT));
  872.     cf.lStructSize = sizeof(CHOOSEFONT);
  873.     cf.hwndOwner = lptw->hWndParent;
  874.     _fstrncpy(lf.lfFaceName,lptw->fontname,LF_FACESIZE);
  875.     if ( (p = _fstrstr(lptw->fontname," Bold")) != (LPSTR)NULL ) {
  876.         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
  877.         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
  878.     }
  879.     else if ( (p = _fstrstr(lptw->fontname," Italic")) != (LPSTR)NULL ) {
  880.         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
  881.         lf.lfFaceName[ (unsigned int)(p-lptw->fontname) ] = '\0';
  882.     }
  883.     else
  884.         _fstrcpy(lpszStyle,"Regular");
  885.     cf.lpszStyle = lpszStyle;
  886.     hdc = GetDC(lptw->hWndText);
  887.     lf.lfHeight = -MulDiv(lptw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  888.     ReleaseDC(lptw->hWndText, hdc);
  889.     lf.lfPitchAndFamily = FIXED_PITCH;
  890.     cf.lpLogFont = &lf;
  891.     cf.nFontType = SCREEN_FONTTYPE;
  892.     cf.Flags = CF_SCREENFONTS | CF_FIXEDPITCHONLY | CF_INITTOLOGFONTSTRUCT | CF_USESTYLE;
  893.     if (ChooseFont(&cf)) {
  894.         RECT rect;
  895.         _fstrcpy(lptw->fontname,lf.lfFaceName);
  896.         lptw->fontsize = cf.iPointSize / 10;
  897.         if (cf.nFontType & BOLD_FONTTYPE)
  898.             lstrcat(lptw->fontname," Bold");
  899.         if (cf.nFontType & ITALIC_FONTTYPE)
  900.             lstrcat(lptw->fontname," Italic");
  901.         TextMakeFont(lptw);
  902.         /* force a window update */
  903.         GetClientRect(lptw->hWndText, (LPRECT) &rect);
  904.         SendMessage(lptw->hWndText, WM_SIZE, SIZE_RESTORED, 
  905.             MAKELPARAM(rect.right-rect.left, rect.bottom-rect.top));
  906.         GetClientRect(lptw->hWndText, (LPRECT) &rect);
  907.         InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
  908.         UpdateWindow(lptw->hWndText);
  909.     }
  910. #endif
  911. }
  912.  
  913.  
  914. /* parent overlapped window */
  915. LRESULT CALLBACK _export
  916. WndParentProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  917. {
  918.     HDC hdc;
  919.     PAINTSTRUCT ps;
  920.     RECT rect;
  921.     LPTW lptw;
  922.  
  923.     lptw = (LPTW)GetWindowLong(hwnd, 0);
  924.  
  925.     switch(message) {
  926.         case WM_SYSCOMMAND:
  927.             switch(LOWORD(wParam))
  928.             {
  929.                 case M_COPY_CLIP:
  930.                 case M_PASTE:
  931.                 case M_CHOOSE_FONT:
  932.                 case M_SYSCOLORS:
  933.                 case M_WRITEINI:
  934.                 case M_ABOUT:
  935.                   SendMessage(lptw->hWndText, WM_COMMAND, wParam, lParam);
  936.             }
  937.             break;
  938.         case WM_SETFOCUS: 
  939.             if (IsWindow(lptw->hWndText)) {
  940.                 SetFocus(lptw->hWndText);
  941.                 return(0);
  942.             }
  943.             break;
  944.         case WM_GETMINMAXINFO:
  945.             {
  946.             POINT far * MMinfo = (POINT far *)lParam;
  947.             TEXTMETRIC tm;
  948.             hdc = GetDC(hwnd);
  949.             SelectFont(hdc, GetStockFont(OEM_FIXED_FONT));
  950.             GetTextMetrics(hdc,(LPTEXTMETRIC)&tm);
  951.             ReleaseDC(hwnd,hdc);
  952.             /* minimum size */
  953.             MMinfo[3].x = ScreenMinSize.x*tm.tmAveCharWidth
  954.                 + GetSystemMetrics(SM_CXVSCROLL) + 2*GetSystemMetrics(SM_CXFRAME);
  955.             MMinfo[3].y = ScreenMinSize.y*tm.tmHeight
  956.                 + GetSystemMetrics(SM_CYHSCROLL) + 2*GetSystemMetrics(SM_CYFRAME)
  957.                 + GetSystemMetrics(SM_CYCAPTION);
  958.             }
  959.             return(0);
  960.         case WM_SIZE:
  961.             SetWindowPos(lptw->hWndText, (HWND)NULL, 0, lptw->ButtonHeight,
  962.                 LOWORD(lParam), HIWORD(lParam)-lptw->ButtonHeight, 
  963.                 SWP_NOZORDER | SWP_NOACTIVATE);
  964.             return(0);
  965.         case WM_COMMAND:
  966.             if (IsWindow(lptw->hWndText))
  967.                 SetFocus(lptw->hWndText);
  968.             SendMessage(lptw->hWndText, message, wParam, lParam); /* pass on menu commands */
  969.             return(0);
  970.         case WM_PAINT:
  971.             {
  972.             hdc = BeginPaint(hwnd, &ps);
  973.             if (lptw->ButtonHeight) {
  974.                 HBRUSH hbrush;
  975.                 GetClientRect(hwnd, &rect);
  976.                 hbrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
  977.                 rect.bottom = lptw->ButtonHeight-1;
  978.                 FillRect(hdc, &rect, hbrush);
  979.                 DeleteBrush(hbrush);
  980.                 SelectPen(hdc, GetStockPen(BLACK_PEN));
  981.                 MoveTo(hdc, rect.left, lptw->ButtonHeight-1);
  982.                 LineTo(hdc, rect.right, lptw->ButtonHeight-1);
  983.             }
  984.             EndPaint(hwnd, &ps);
  985.             return 0;
  986.             }
  987. #if WINVER >= 0x030a
  988.         case WM_DROPFILES:
  989.             {
  990.             WORD version = LOWORD(GetVersion());
  991.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  992.                 DragFunc(lptw, (HDROP)wParam);
  993.             }
  994.             break;
  995. #endif
  996.         case WM_CREATE:
  997.             {
  998.             RECT crect, wrect;
  999.             TEXTMETRIC tm;
  1000.             lptw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
  1001.             SetWindowLong(hwnd, 0, (LONG)lptw);
  1002.             lptw->hWndParent = hwnd;
  1003.             /* get character size */
  1004.             TextMakeFont(lptw);
  1005.             hdc = GetDC(hwnd);
  1006.             SelectFont(hdc, lptw->hfont);
  1007.             GetTextMetrics(hdc,(LPTEXTMETRIC)&tm);
  1008.             lptw->CharSize.y = tm.tmHeight;
  1009.             lptw->CharSize.x = tm.tmAveCharWidth;
  1010.             lptw->CharAscent = tm.tmAscent;
  1011.             ReleaseDC(hwnd,hdc);
  1012.             GetClientRect(hwnd, &crect);
  1013.             if ( (lptw->CharSize.y*lptw->ScreenSize.y < crect.bottom)
  1014.               || (lptw->CharSize.x*lptw->ScreenSize.x < crect.right) ) {
  1015.                 /* shrink size */
  1016.                 GetWindowRect(lptw->hWndParent,&wrect);
  1017.                 MoveWindow(lptw->hWndParent, wrect.left, wrect.top,
  1018.                  wrect.right-wrect.left + (lptw->CharSize.x*lptw->ScreenSize.x - crect.right),
  1019.                  wrect.bottom-wrect.top + (lptw->CharSize.y*lptw->ScreenSize.y+lptw->ButtonHeight - crect.bottom),
  1020.                  TRUE);
  1021.             }
  1022.             }
  1023. #if WINVER >= 0x030a
  1024.             {
  1025.             WORD version = LOWORD(GetVersion());
  1026.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1027.                 if ( (lptw->DragPre!=(LPSTR)NULL) && (lptw->DragPost!=(LPSTR)NULL) )
  1028.                     DragAcceptFiles(hwnd, TRUE);
  1029.             }
  1030. #endif
  1031.             break;
  1032.         case WM_DESTROY:
  1033. #if WINVER >= 0x030a
  1034.             {
  1035.             WORD version = LOWORD(GetVersion());
  1036.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1037.                 DragAcceptFiles(hwnd, FALSE);
  1038.             }
  1039. #endif
  1040.             DeleteFont(lptw->hfont);
  1041.             lptw->hfont = 0;
  1042.             break;
  1043.         case WM_CLOSE:
  1044.             if (lptw->shutdown) {
  1045.                 FARPROC lpShutDown = lptw->shutdown;
  1046.                 (*lpShutDown)();
  1047.             }
  1048.             break;
  1049.     }
  1050.     return DefWindowProc(hwnd, message, wParam, lParam);
  1051. }
  1052.  
  1053. /* child text window */
  1054. LRESULT CALLBACK _export
  1055. WndTextProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1056. {
  1057.     HDC hdc;
  1058.     PAINTSTRUCT ps;
  1059.     RECT rect;
  1060.     int nYinc, nXinc;
  1061.     LPTW lptw;
  1062.  
  1063.     lptw = (LPTW)GetWindowLong(hwnd, 0);
  1064.  
  1065.     switch(message) {
  1066.         case WM_SETFOCUS: 
  1067.             lptw->bFocus = TRUE;
  1068.             CreateCaret(hwnd, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
  1069.             SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
  1070.                 lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent
  1071.                  - lptw->CaretHeight - lptw->ScrollPos.y);
  1072.             if (lptw->bGetCh)
  1073.                 ShowCaret(hwnd);
  1074.             break;
  1075.         case WM_KILLFOCUS: 
  1076.             DestroyCaret();
  1077.             lptw->bFocus = FALSE;
  1078.             break;
  1079.         case WM_SIZE:
  1080.             lptw->ClientSize.y = HIWORD(lParam);
  1081.             lptw->ClientSize.x = LOWORD(lParam);
  1082.  
  1083.             lptw->ScrollMax.y = max(0, lptw->CharSize.y*lptw->ScreenSize.y - lptw->ClientSize.y);
  1084.             lptw->ScrollPos.y = min(lptw->ScrollPos.y, lptw->ScrollMax.y);
  1085.  
  1086.             SetScrollRange(hwnd, SB_VERT, 0, lptw->ScrollMax.y, FALSE);
  1087.             SetScrollPos(hwnd, SB_VERT, lptw->ScrollPos.y, TRUE);
  1088.  
  1089.             lptw->ScrollMax.x = max(0, lptw->CharSize.x*lptw->ScreenSize.x - lptw->ClientSize.x);
  1090.             lptw->ScrollPos.x = min(lptw->ScrollPos.x, lptw->ScrollMax.x);
  1091.  
  1092.             SetScrollRange(hwnd, SB_HORZ, 0, lptw->ScrollMax.x, FALSE);
  1093.             SetScrollPos(hwnd, SB_HORZ, lptw->ScrollPos.x, TRUE);
  1094.  
  1095.             if (lptw->bFocus && lptw->bGetCh) {
  1096.                 SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
  1097.                     lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent 
  1098.                     - lptw->CaretHeight - lptw->ScrollPos.y);
  1099.                 ShowCaret(hwnd);
  1100.             }
  1101.             return(0);
  1102.         case WM_VSCROLL:
  1103.             switch(LOWORD(wParam)) {
  1104.                 case SB_TOP:
  1105.                     nYinc = -lptw->ScrollPos.y;
  1106.                     break;
  1107.                 case SB_BOTTOM:
  1108.                     nYinc = lptw->ScrollMax.y - lptw->ScrollPos.y;
  1109.                     break;
  1110.                 case SB_LINEUP:
  1111.                     nYinc = -lptw->CharSize.y;
  1112.                     break;
  1113.                 case SB_LINEDOWN:
  1114.                     nYinc = lptw->CharSize.y;
  1115.                     break;
  1116.                 case SB_PAGEUP:
  1117.                     nYinc = min(-1,-lptw->ClientSize.y);
  1118.                     break;
  1119.                 case SB_PAGEDOWN:
  1120.                     nYinc = max(1,lptw->ClientSize.y);
  1121.                     break;
  1122.                 case SB_THUMBPOSITION:
  1123.                     nYinc = LOWORD(lParam) - lptw->ScrollPos.y;
  1124.                     break;
  1125.                 default:
  1126.                     nYinc = 0;
  1127.                 }
  1128.             if ( (nYinc = max(-lptw->ScrollPos.y, 
  1129.                 min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y)))
  1130.                 != 0 ) {
  1131.                 lptw->ScrollPos.y += nYinc;
  1132.                 ScrollWindow(hwnd,0,-nYinc,NULL,NULL);
  1133.                 SetScrollPos(hwnd,SB_VERT,lptw->ScrollPos.y,TRUE);
  1134.                 UpdateWindow(hwnd);
  1135.             }
  1136.             return(0);
  1137.         case WM_HSCROLL:
  1138.             switch(LOWORD(wParam)) {
  1139.                 case SB_LINEUP:
  1140.                     nXinc = -lptw->CharSize.x;
  1141.                     break;
  1142.                 case SB_LINEDOWN:
  1143.                     nXinc = lptw->CharSize.x;
  1144.                     break;
  1145.                 case SB_PAGEUP:
  1146.                     nXinc = min(-1,-lptw->ClientSize.x);
  1147.                     break;
  1148.                 case SB_PAGEDOWN:
  1149.                     nXinc = max(1,lptw->ClientSize.x);
  1150.                     break;
  1151.                 case SB_THUMBPOSITION:
  1152.                     nXinc = LOWORD(lParam) - lptw->ScrollPos.x;
  1153.                     break;
  1154.                 default:
  1155.                     nXinc = 0;
  1156.                 }
  1157.             if ( (nXinc = max(-lptw->ScrollPos.x, 
  1158.                 min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x)))
  1159.                 != 0 ) {
  1160.                 lptw->ScrollPos.x += nXinc;
  1161.                 ScrollWindow(hwnd,-nXinc,0,NULL,NULL);
  1162.                 SetScrollPos(hwnd,SB_HORZ,lptw->ScrollPos.x,TRUE);
  1163.                 UpdateWindow(hwnd);
  1164.             }
  1165.             return(0);
  1166.         case WM_KEYDOWN:
  1167.             if (GetKeyState(VK_SHIFT) < 0) {
  1168.               switch(wParam) {
  1169.                 case VK_HOME:
  1170.                     SendMessage(hwnd, WM_VSCROLL, SB_TOP, (LPARAM)0);
  1171.                     break;
  1172.                 case VK_END:
  1173.                     SendMessage(hwnd, WM_VSCROLL, SB_BOTTOM, (LPARAM)0);
  1174.                     break;
  1175.                 case VK_PRIOR:
  1176.                     SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, (LPARAM)0);
  1177.                     break;
  1178.                 case VK_NEXT:
  1179.                     SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, (LPARAM)0);
  1180.                     break;
  1181.                 case VK_UP:
  1182.                     SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, (LPARAM)0);
  1183.                     break;
  1184.                 case VK_DOWN:
  1185.                     SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, (LPARAM)0);
  1186.                     break;
  1187.                 case VK_LEFT:
  1188.                     SendMessage(hwnd, WM_HSCROLL, SB_LINEUP, (LPARAM)0);
  1189.                     break;
  1190.                 case VK_RIGHT:
  1191.                     SendMessage(hwnd, WM_HSCROLL, SB_LINEDOWN, (LPARAM)0);
  1192.                     break;
  1193.               }
  1194.             }
  1195.             else {
  1196.               switch(wParam) {
  1197.                 case VK_HOME:
  1198.                 case VK_END:
  1199.                 case VK_PRIOR:
  1200.                 case VK_NEXT:
  1201.                 case VK_UP:
  1202.                 case VK_DOWN:
  1203.                 case VK_LEFT:
  1204.                 case VK_RIGHT:
  1205.                 case VK_DELETE:
  1206.                 { /* store key in circular buffer */
  1207.                 long count;
  1208.                     count = lptw->KeyBufIn - lptw->KeyBufOut;
  1209.                     if (count < 0) count += lptw->KeyBufSize;
  1210.                     if (count < lptw->KeyBufSize-2) {
  1211.                         *lptw->KeyBufIn++ = 0;
  1212.                         if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
  1213.                             lptw->KeyBufIn = lptw->KeyBuf;    /* wrap around */
  1214.                         *lptw->KeyBufIn++ = HIWORD(lParam) & 0xff;
  1215.                         if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
  1216.                             lptw->KeyBufIn = lptw->KeyBuf;    /* wrap around */
  1217.                     }
  1218.                 }
  1219.               }
  1220.             }
  1221.             break;
  1222.         case WM_RBUTTONDOWN:
  1223.             {
  1224.             POINT pt;
  1225.             pt.x = LOWORD(lParam);
  1226.             pt.y = HIWORD(lParam);
  1227.             ClientToScreen(hwnd,&pt);
  1228.             TrackPopupMenu(lptw->hPopMenu, TPM_LEFTALIGN, 
  1229.                 pt.x, pt.y, 0, hwnd, NULL);
  1230.             }
  1231.             return(0);
  1232.         case WM_LBUTTONDOWN:
  1233.             { /* start marking text */
  1234.             POINT pt;
  1235.             pt.x = LOWORD(lParam);
  1236.             pt.y = HIWORD(lParam);
  1237.             pt.x = (pt.x + lptw->ScrollPos.x)/lptw->CharSize.x;
  1238.             pt.y = (pt.y + lptw->ScrollPos.y)/lptw->CharSize.y;
  1239.             ClearMark(lptw, pt);
  1240.             }
  1241.             SetCapture(hwnd);    /* track the mouse */
  1242.             lptw->Marking = TRUE;
  1243.             break;
  1244.         case WM_LBUTTONUP:
  1245.             { /* finish marking text */
  1246.             /* ensure begin mark is before end mark */
  1247.             ReleaseCapture();
  1248.             lptw->Marking = FALSE;
  1249.             if ((lptw->ScreenSize.x*lptw->MarkBegin.y + lptw->MarkBegin.x) >
  1250.                 (lptw->ScreenSize.x*lptw->MarkEnd.y   + lptw->MarkEnd.x)) {
  1251.                 POINT tmp;
  1252.                 tmp.x = lptw->MarkBegin.x;
  1253.                 tmp.y = lptw->MarkBegin.y;
  1254.                 lptw->MarkBegin.x = lptw->MarkEnd.x;
  1255.                 lptw->MarkBegin.y = lptw->MarkEnd.y;
  1256.                 lptw->MarkEnd.x   = tmp.x;
  1257.                 lptw->MarkEnd.y   = tmp.y;
  1258.             }
  1259.             }
  1260.             break;
  1261.         case WM_MOUSEMOVE:
  1262.             if ( (wParam & MK_LBUTTON) && lptw->Marking ) {
  1263.             RECT rect;
  1264.             POINT pt;
  1265.             pt.x = LOWORD(lParam);
  1266.             pt.y = HIWORD(lParam);
  1267.             GetClientRect(hwnd, &rect);
  1268.             if (PtInRect(&rect, pt)) {
  1269.                 pt.x = (pt.x + lptw->ScrollPos.x)/lptw->CharSize.x;
  1270.                 pt.y = (pt.y + lptw->ScrollPos.y)/lptw->CharSize.y;
  1271.                 UpdateMark(lptw, pt);
  1272.             }
  1273.             else {
  1274.               int nXinc;
  1275.               int nYinc;
  1276.               do {
  1277.                 nXinc = 0;
  1278.                 nYinc = 0;
  1279.                 if (pt.x > rect.right) {
  1280.                     nXinc = lptw->CharSize.x * 4;
  1281.                     pt.x = (rect.right + lptw->ScrollPos.x)/lptw->CharSize.x + 2;
  1282.                 }
  1283.                 else if (pt.x < rect.left) {
  1284.                     nXinc = -lptw->CharSize.x * 4;
  1285.                     pt.x = (rect.left + lptw->ScrollPos.x)/lptw->CharSize.x - 2;
  1286.                 }
  1287.                 else
  1288.                     pt.x = (pt.x + lptw->ScrollPos.x)/lptw->CharSize.x;
  1289.                 if (pt.y > rect.bottom) {
  1290.                     nYinc = lptw->CharSize.y;
  1291.                     pt.y = (rect.bottom + lptw->ScrollPos.y)/lptw->CharSize.y + 1;
  1292.                 }
  1293.                 else if (pt.y < rect.top) {
  1294.                     nYinc = -lptw->CharSize.y;
  1295.                     pt.y = (rect.top + lptw->ScrollPos.y)/lptw->CharSize.y - 1;
  1296.                 }
  1297.                 else
  1298.                     pt.y = (pt.y + lptw->ScrollPos.y)/lptw->CharSize.y;
  1299.                 LimitMark(lptw, &pt);
  1300.                 nXinc = max(nXinc, -lptw->ScrollPos.x);
  1301.                 nYinc = max(nYinc, -lptw->ScrollPos.y);
  1302.                 nYinc = min(nYinc, lptw->ScrollMax.y - lptw->ScrollPos.y);
  1303.                 nXinc = min(nXinc, lptw->ScrollMax.x - lptw->ScrollPos.x);
  1304.                 if (nYinc || nXinc) {
  1305.                     lptw->ScrollPos.y += nYinc;
  1306.                     lptw->ScrollPos.x += nXinc;
  1307.                     ScrollWindow(lptw->hWndText,-nXinc,-nYinc,NULL,NULL);
  1308.                     SetScrollPos(lptw->hWndText,SB_VERT,lptw->ScrollPos.y,TRUE);
  1309.                     SetScrollPos(lptw->hWndText,SB_HORZ,lptw->ScrollPos.x,TRUE);
  1310.                     UpdateWindow(lptw->hWndText);
  1311.                 }
  1312.                 UpdateMark(lptw, pt);
  1313.                 GetCursorPos(&pt);
  1314.                 ScreenToClient(hwnd, &pt);
  1315.               }
  1316.               while( (nYinc || nXinc) && !PtInRect(&rect, pt) &&
  1317.                 (GetAsyncKeyState(VK_LBUTTON) < 0) );
  1318.             }
  1319.             }
  1320.             break;
  1321.         case WM_CHAR:
  1322.             { /* store key in circular buffer */
  1323.             long count;
  1324.                 count = lptw->KeyBufIn - lptw->KeyBufOut;
  1325.                 if (count < 0) count += lptw->KeyBufSize;
  1326.                 if (count < lptw->KeyBufSize-1) {
  1327.                     *lptw->KeyBufIn++ = wParam;
  1328.                     if (lptw->KeyBufIn - lptw->KeyBuf >= lptw->KeyBufSize)
  1329.                         lptw->KeyBufIn = lptw->KeyBuf;    /* wrap around */
  1330.                 }
  1331.             }
  1332.             return(0);
  1333.         case WM_COMMAND:
  1334.             if (LOWORD(wParam) < NUMMENU)
  1335.                 SendMacro(lptw, LOWORD(wParam));
  1336.             else
  1337.             switch(LOWORD(wParam))
  1338.             {
  1339.                 case M_COPY_CLIP:
  1340.                     TextCopyClip(lptw);
  1341.                     return 0;
  1342.                 case M_PASTE:
  1343.                     {
  1344.                     HGLOBAL hGMem;
  1345.                     BYTE FAR *cbuf;
  1346.                     TEXTMETRIC tm;
  1347.                     UINT type;
  1348.                     /* find out what type to get from clipboard */
  1349.                     hdc = GetDC(hwnd);
  1350.                     SelectFont(hdc, lptw->hfont);
  1351.                     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
  1352.                     if (tm.tmCharSet == OEM_CHARSET)
  1353.                         type = CF_OEMTEXT;
  1354.                     else
  1355.                         type = CF_TEXT;
  1356.                     ReleaseDC(lptw->hWndText, hdc);
  1357.                     /* now get it from clipboard */
  1358.                     OpenClipboard(hwnd);
  1359.                     hGMem = GetClipboardData(type);
  1360.                     if (hGMem) {
  1361.                         cbuf = (BYTE FAR *) GlobalLock(hGMem);
  1362.                         while (*cbuf) {
  1363.                             if (*cbuf != '\n')
  1364.                                 SendMessage(lptw->hWndText,WM_CHAR,*cbuf,1L);
  1365.                             cbuf++;
  1366.                         }
  1367.                         GlobalUnlock(hGMem);
  1368.                     }
  1369.                     CloseClipboard();
  1370.                     return 0;
  1371.                     }
  1372.                 case M_CHOOSE_FONT:
  1373.                     TextSelectFont(lptw);
  1374.                     return 0;
  1375.                 case M_SYSCOLORS:
  1376.                     lptw->bSysColors = !lptw->bSysColors;
  1377.                     if (lptw->bSysColors) 
  1378.                         CheckMenuItem(lptw->hPopMenu, M_SYSCOLORS, MF_BYCOMMAND | MF_CHECKED);
  1379.                     else
  1380.                         CheckMenuItem(lptw->hPopMenu, M_SYSCOLORS, MF_BYCOMMAND | MF_UNCHECKED);
  1381.                     SendMessage(hwnd, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0);
  1382.                     InvalidateRect(hwnd, (LPRECT)NULL, 1);
  1383.                     UpdateWindow(hwnd);
  1384.                     return 0;
  1385.                 case M_WRITEINI:
  1386.                     WriteTextIni(lptw);
  1387.                     return 0;
  1388.                 case M_ABOUT:
  1389.                     AboutBox(hwnd,lptw->AboutText);
  1390.                     return 0;
  1391.             }
  1392.             return(0);
  1393.         case WM_SYSCOLORCHANGE:
  1394.             DeleteBrush(lptw->hbrBackground);
  1395.             lptw->hbrBackground = CreateSolidBrush(lptw->bSysColors ? 
  1396.                 GetSysColor(COLOR_WINDOW) : RGB(0,0,0));
  1397.             return(0);
  1398.         case WM_ERASEBKGND:
  1399.             return(1);    /* we will erase it ourselves */
  1400.         case WM_PAINT:
  1401.             {
  1402.             POINT source, width, dest;
  1403.             POINT MarkBegin, MarkEnd;
  1404.             hdc = BeginPaint(hwnd, &ps);
  1405.             if (ps.fErase)
  1406.                 FillRect(hdc, &ps.rcPaint, lptw->hbrBackground);
  1407.             SelectFont(hdc, lptw->hfont);
  1408.             SetMapMode(hdc, MM_TEXT);
  1409.             SetBkMode(hdc,OPAQUE);
  1410.             GetClientRect(hwnd, &rect);
  1411.             source.x = (rect.left + lptw->ScrollPos.x) / lptw->CharSize.x;        /* source */
  1412.             source.y = (rect.top + lptw->ScrollPos.y) / lptw->CharSize.y;
  1413.             dest.x = source.x * lptw->CharSize.x - lptw->ScrollPos.x;                 /* destination */
  1414.             dest.y = source.y * lptw->CharSize.y - lptw->ScrollPos.y;
  1415.             width.x = ((rect.right  + lptw->ScrollPos.x + lptw->CharSize.x - 1) / lptw->CharSize.x) - source.x; /* width */
  1416.             width.y = ((rect.bottom + lptw->ScrollPos.y + lptw->CharSize.y - 1) / lptw->CharSize.y) - source.y;
  1417.             if (source.x < 0)
  1418.                 source.x = 0;
  1419.             if (source.y < 0)
  1420.                 source.y = 0;
  1421.             if (source.x+width.x > lptw->ScreenSize.x)
  1422.                 width.x = lptw->ScreenSize.x - source.x;
  1423.             if (source.y+width.y > lptw->ScreenSize.y)
  1424.                 width.y = lptw->ScreenSize.y - source.y;
  1425.             /* ensure begin mark is before end mark */
  1426.             if ((lptw->ScreenSize.x*lptw->MarkBegin.y + lptw->MarkBegin.x) >
  1427.                 (lptw->ScreenSize.x*lptw->MarkEnd.y   + lptw->MarkEnd.x)) {
  1428.                 MarkBegin.x = lptw->MarkEnd.x;
  1429.                 MarkBegin.y = lptw->MarkEnd.y;
  1430.                 MarkEnd.x   = lptw->MarkBegin.x;
  1431.                 MarkEnd.y   = lptw->MarkBegin.y;
  1432.             }
  1433.             else {
  1434.                 MarkBegin.x = lptw->MarkBegin.x;
  1435.                 MarkBegin.y = lptw->MarkBegin.y;
  1436.                 MarkEnd.x   = lptw->MarkEnd.x;
  1437.                 MarkEnd.y   = lptw->MarkEnd.y;
  1438.             }
  1439.             /* for each line */
  1440.             while (width.y>0) {
  1441.                 if ( (source.y >= MarkBegin.y) && (source.y <= MarkEnd.y) ) {
  1442.                     int start, end;
  1443.                     int count, offset;
  1444.                     if (source.y == MarkBegin.y)
  1445.                         start = MarkBegin.x;
  1446.                     else
  1447.                         start = 0;
  1448.                     if (source.y == MarkEnd.y)
  1449.                         end = MarkEnd.x;
  1450.                     else
  1451.                         end = lptw->ScreenSize.x;
  1452.                     /* do stuff before marked text */
  1453.                     offset = 0;
  1454.                     count = start - source.x;
  1455.                     if (count > 0)
  1456.                       DoLine(lptw, hdc, dest.x, dest.y, 
  1457.                         source.y*lptw->ScreenSize.x + source.x, count);
  1458.                     /* then the marked text */
  1459.                     offset += count;
  1460.                     count = end - start;
  1461.                     if ((count > 0) && (offset < width.x)){
  1462.                       if (lptw->bSysColors) {
  1463.                         SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
  1464.                         SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
  1465.                       }
  1466.                       else {
  1467.                         SetTextColor(hdc, MARKFORE);
  1468.                         SetBkColor(hdc, MARKBACK);
  1469.                       }
  1470.                       TextOut(hdc, dest.x + lptw->CharSize.x*offset, dest.y, 
  1471.                         (LPSTR)(lptw->ScreenBuffer + source.y*lptw->ScreenSize.x 
  1472.                         + source.x + offset), count);
  1473.                     }
  1474.                     /* then stuff after marked text */
  1475.                     offset += count;
  1476.                     count = width.x + source.x - end;
  1477.                     if ((count > 0) && (offset < width.x))
  1478.                       DoLine(lptw, hdc, dest.x + lptw->CharSize.x*offset, dest.y, 
  1479.                         source.y*lptw->ScreenSize.x + source.x + offset, count);
  1480.                 }
  1481.                 else {
  1482.                     DoLine(lptw, hdc, dest.x, dest.y, 
  1483.                         source.y*lptw->ScreenSize.x + source.x, width.x);
  1484.                 }
  1485.                 dest.y += lptw->CharSize.y;
  1486.                 source.y++;
  1487.                 width.y--;
  1488.             }
  1489.             EndPaint(hwnd, &ps);
  1490.             return 0;
  1491.             }
  1492.         case WM_CREATE:
  1493.             lptw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
  1494.             SetWindowLong(hwnd, 0, (LONG)lptw);
  1495.             lptw->hWndText = hwnd;
  1496.             break;
  1497.         case WM_DESTROY:
  1498.             DeleteBrush(lptw->hbrBackground);
  1499.             break;
  1500.     }
  1501.     return DefWindowProc(hwnd, message, wParam, lParam);
  1502. }
  1503.  
  1504.  
  1505. /* ================================== */
  1506. /* replacement stdio routines */
  1507.  
  1508. /* TRUE if key hit, FALSE if no key */
  1509. int WDPROC
  1510. TextKBHit(LPTW lptw)
  1511. {
  1512.     return (lptw->KeyBufIn != lptw->KeyBufOut);
  1513. }
  1514.  
  1515. /* get character from keyboard, no echo */
  1516. /* need to add extended codes */
  1517. int WDPROC
  1518. TextGetCh(LPTW lptw)
  1519. {
  1520.     int ch;
  1521.     TextToCursor(lptw);
  1522.     lptw->bGetCh = TRUE;
  1523.     if (lptw->bFocus) {
  1524.         SetCaretPos(lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x,
  1525.             lptw->CursorPos.y*lptw->CharSize.y + lptw->CharAscent 
  1526.             - lptw->CaretHeight - lptw->ScrollPos.y);
  1527.         ShowCaret(lptw->hWndText);
  1528.     }
  1529.     do {
  1530.         TextMessage();
  1531.     } while (!TextKBHit(lptw));
  1532.     ch = *lptw->KeyBufOut++;
  1533.     if (ch=='\r')
  1534.         ch = '\n';
  1535.     if (lptw->KeyBufOut - lptw->KeyBuf >= lptw->KeyBufSize)
  1536.         lptw->KeyBufOut = lptw->KeyBuf;    /* wrap around */
  1537.     if (lptw->bFocus)
  1538.         HideCaret(lptw->hWndText);
  1539.     lptw->bGetCh = FALSE;
  1540.     return ch;
  1541. }
  1542.  
  1543. /* get character from keyboard, with echo */
  1544. int WDPROC
  1545. TextGetChE(LPTW lptw)
  1546. {
  1547. int ch;
  1548.     ch = TextGetCh(lptw);
  1549.     TextPutCh(lptw, (BYTE)ch);
  1550.     return ch;
  1551. }
  1552.  
  1553. LPSTR WDPROC
  1554. TextGetS(LPTW lptw, LPSTR str, unsigned int size)
  1555. {
  1556.     LPSTR next = str;
  1557.     while (--size>0) {
  1558.         switch(*next = TextGetChE(lptw)) {
  1559.             case EOF:
  1560.                 *next = NULL;
  1561.                 if (next == str) return (char *)NULL;
  1562.                 return str;
  1563.             case '\n':
  1564.                 *(next+1) = NULL;
  1565.                 return str;
  1566.             case 0x08:
  1567.             case 0x7f:
  1568.                 if (next > str)
  1569.                     --next;
  1570.                 break;
  1571.             default:
  1572.                 ++next;
  1573.         }
  1574.     }
  1575.     *next = NULL;
  1576.     return str;
  1577. }
  1578.  
  1579. int WDPROC
  1580. TextPutS(LPTW lptw, LPSTR str)
  1581. {
  1582.     TextPutStr(lptw, str);
  1583.     return str[_fstrlen(str)-1];
  1584. }
  1585.  
  1586. /* ================================== */
  1587. /* routines added for elvis */
  1588.  
  1589. void WDPROC
  1590. TextGotoXY(LPTW lptw, int x, int y)
  1591. {
  1592.     lptw->CursorPos.x = x;
  1593.     lptw->CursorPos.y = y;
  1594. }
  1595.  
  1596. int  WDPROC
  1597. TextWhereX(LPTW lptw)
  1598. {
  1599.     return lptw->CursorPos.x;
  1600. }
  1601.  
  1602. int  WDPROC
  1603. TextWhereY(LPTW lptw)
  1604. {
  1605.     return lptw->CursorPos.y;
  1606. }
  1607.  
  1608. void WDPROC
  1609. TextCursorHeight(LPTW lptw, int height)
  1610. {
  1611.     lptw->CaretHeight = height;
  1612.     if (lptw->bFocus)
  1613.         CreateCaret(lptw->hWndText, 0, lptw->CharSize.x, 2+lptw->CaretHeight);
  1614. }
  1615.  
  1616. void WDPROC
  1617. TextClearEOL(LPTW lptw)
  1618. {
  1619. HDC hdc;
  1620. int xpos, ypos;
  1621. int from, len;
  1622. POINT pt;
  1623.     pt.x = pt.y = 0;
  1624.     ClearMark(lptw, pt);
  1625.     from = lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
  1626.     len = lptw->ScreenSize.x-lptw->CursorPos.x;
  1627.     _fmemset(lptw->ScreenBuffer + from, ' ', len);
  1628.     _fmemset(lptw->AttrBuffer + from, NOTEXT, len);
  1629.     xpos = lptw->CursorPos.x*lptw->CharSize.x - lptw->ScrollPos.x;
  1630.     ypos = lptw->CursorPos.y*lptw->CharSize.y - lptw->ScrollPos.y;
  1631.     hdc = GetDC(lptw->hWndText);
  1632.     if (lptw->bSysColors) {
  1633.         SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  1634.         SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
  1635.     }
  1636.     else {
  1637.         SetTextColor(hdc, TextFore(lptw->Attr));
  1638.         SetBkColor(hdc, TextBack(lptw->Attr));
  1639.     }
  1640.     SelectFont(hdc, (lptw->hfont));
  1641.     TextOut(hdc,xpos,ypos,
  1642.         (LPSTR)(lptw->ScreenBuffer + lptw->CursorPos.y*lptw->ScreenSize.x + 
  1643.         lptw->CursorPos.x), lptw->ScreenSize.x-lptw->CursorPos.x);
  1644.     (void)ReleaseDC(lptw->hWndText,hdc);
  1645. }
  1646.  
  1647. void WDPROC
  1648. TextClearEOS(LPTW lptw)
  1649. {
  1650. RECT rect;
  1651. int from, len;
  1652. POINT pt;
  1653.     pt.x = pt.y = 0;
  1654.     ClearMark(lptw, pt);
  1655.     from = lptw->CursorPos.y*lptw->ScreenSize.x + lptw->CursorPos.x;
  1656.     len = lptw->ScreenSize.x-lptw->CursorPos.x + 
  1657.             (lptw->ScreenSize.y-lptw->CursorPos.y-1)*lptw->ScreenSize.x;
  1658.     _fmemset(lptw->ScreenBuffer + from, ' ', len);
  1659.     _fmemset(lptw->AttrBuffer + from, NOTEXT, len);
  1660.     GetClientRect(lptw->hWndText, (LPRECT) &rect);
  1661.     InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
  1662.     UpdateWindow(lptw->hWndText);
  1663. }
  1664.  
  1665. void WDPROC
  1666. TextInsertLine(LPTW lptw)
  1667. {
  1668. RECT rect;
  1669. int from, to, len;
  1670. POINT pt;
  1671.     pt.x = pt.y = 0;
  1672.     ClearMark(lptw, pt);
  1673.     from = lptw->CursorPos.y*lptw->ScreenSize.x,
  1674.     to = (lptw->CursorPos.y+1)*lptw->ScreenSize.x;
  1675.     len = (lptw->ScreenSize.y-lptw->CursorPos.y-1)*lptw->ScreenSize.x;
  1676.     _fmemmove(lptw->ScreenBuffer + to, lptw->ScreenBuffer + from, len);
  1677.     _fmemmove(lptw->AttrBuffer + to, lptw->AttrBuffer + from, len);
  1678.     _fmemset(lptw->ScreenBuffer + from, ' ', lptw->ScreenSize.x);
  1679.     _fmemset(lptw->AttrBuffer + from, NOTEXT, lptw->ScreenSize.x);
  1680.     GetClientRect(lptw->hWndText, (LPRECT) &rect);
  1681.     InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
  1682.     UpdateWindow(lptw->hWndText);
  1683.     if (lptw->CursorFlag)
  1684.         TextToCursor(lptw);
  1685. }
  1686.  
  1687. void WDPROC
  1688. TextDeleteLine(LPTW lptw)
  1689. {
  1690. RECT rect;
  1691. int from, to, len;
  1692. POINT pt;
  1693.     pt.x = pt.y = 0;
  1694.     ClearMark(lptw, pt);
  1695.     to = lptw->CursorPos.y*lptw->ScreenSize.x,
  1696.     from = (lptw->CursorPos.y+1)*lptw->ScreenSize.x;
  1697.     len = (lptw->ScreenSize.y-lptw->CursorPos.y-1)*lptw->ScreenSize.x;
  1698.     _fmemmove(lptw->ScreenBuffer + to, lptw->ScreenBuffer + from, len);
  1699.     _fmemmove(lptw->AttrBuffer + to, lptw->AttrBuffer + from, len);
  1700.     from = lptw->ScreenSize.x*(lptw->ScreenSize.y -1);
  1701.     _fmemset(lptw->ScreenBuffer + from, ' ', lptw->ScreenSize.x);
  1702.     _fmemset(lptw->AttrBuffer + from, NOTEXT, lptw->ScreenSize.x);
  1703.     GetClientRect(lptw->hWndText, (LPRECT) &rect);
  1704.     InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
  1705.     UpdateWindow(lptw->hWndText);
  1706.     if (lptw->CursorFlag)
  1707.         TextToCursor(lptw);
  1708. }
  1709.  
  1710. void WDPROC
  1711. TextScrollReverse(LPTW lptw)
  1712. {
  1713. RECT rect;
  1714. int len = lptw->ScreenSize.x * (lptw->ScreenSize.y - 1); 
  1715.     _fmemmove(lptw->ScreenBuffer+lptw->ScreenSize.x, lptw->ScreenBuffer, len);
  1716.     _fmemset(lptw->ScreenBuffer, ' ', lptw->ScreenSize.x);
  1717.     _fmemmove(lptw->AttrBuffer+lptw->ScreenSize.x, lptw->AttrBuffer, len);
  1718.     _fmemset(lptw->AttrBuffer, NOTEXT, lptw->ScreenSize.x);
  1719.     if (lptw->CursorPos.y)
  1720.         lptw->CursorPos.y--;
  1721.     ScrollWindow(lptw->hWndText,0,+lptw->CharSize.y,NULL,NULL);
  1722.     GetClientRect(lptw->hWndText, (LPRECT) &rect);
  1723.     rect.top = lptw->ScreenSize.y*lptw->CharSize.y;
  1724.     if (rect.top < rect.bottom)
  1725.         InvalidateRect(lptw->hWndText, (LPRECT) &rect, 1);
  1726.     lptw->MarkBegin.y++;
  1727.     lptw->MarkEnd.y++;
  1728.     LimitMark(lptw, &lptw->MarkBegin);
  1729.     LimitMark(lptw, &lptw->MarkEnd);
  1730.     UpdateWindow(lptw->hWndText);
  1731. }
  1732.  
  1733. void WDPROC 
  1734. TextAttr(LPTW lptw, BYTE attr)
  1735. {
  1736.     lptw->Attr = attr;
  1737. }
  1738.  
  1739. /* About Box */
  1740. BOOL CALLBACK _export
  1741. AboutDlgProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
  1742. {
  1743.     switch (wMsg) {
  1744.         case WM_INITDIALOG:
  1745.             {
  1746.             char buf[80];
  1747.             GetWindowText(GetParent(hDlg),buf,80);
  1748.             SetDlgItemText(hDlg, AB_TEXT1, buf);
  1749.             SetDlgItemText(hDlg, AB_TEXT2, (LPSTR)lParam);
  1750. #ifdef __DLL__
  1751.             wsprintf(buf,"WGNUPLOT.DLL Version %s",(LPSTR)WGNUPLOTVERSION);
  1752.             SetDlgItemText(hDlg, AB_TEXT3, buf);
  1753. #endif
  1754.             }
  1755.             return TRUE;
  1756.         case WM_DRAWITEM:
  1757.             {
  1758.             LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
  1759. #ifdef WIN32
  1760.             DrawIcon(lpdis->hDC, 0, 0, (HICON)GetClassLong(GetParent(hDlg), GCL_HICON));
  1761. #else
  1762.             DrawIcon(lpdis->hDC, 0, 0, (HICON)GetClassWord(GetParent(hDlg), GCW_HICON));
  1763. #endif
  1764.             }
  1765.             return FALSE;
  1766.         case WM_COMMAND:
  1767.             switch (LOWORD(wParam)) {
  1768.                 case IDCANCEL:
  1769.                 case IDOK:
  1770.                     EndDialog(hDlg, LOWORD(wParam));
  1771.                     return TRUE;
  1772.             }
  1773.             break;
  1774.     }
  1775.     return FALSE;
  1776. }
  1777.  
  1778.  
  1779. void WDPROC
  1780. AboutBox(HWND hwnd, LPSTR str)
  1781. {
  1782. DLGPROC lpfnAboutDlgProc;
  1783. #ifdef __DLL__
  1784.     lpfnAboutDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "AboutDlgProc");
  1785. #else
  1786.     lpfnAboutDlgProc = (DLGPROC)MakeProcInstance((FARPROC)AboutDlgProc, hdllInstance);
  1787. #endif
  1788.     DialogBoxParam(hdllInstance,"AboutDlgBox",hwnd,lpfnAboutDlgProc,(LPARAM)str);
  1789.     EnableWindow(hwnd,TRUE);
  1790. #ifndef __DLL__
  1791.     FreeProcInstance((FARPROC)lpfnAboutDlgProc);
  1792. #endif
  1793. }
  1794.